package org.abc.fund.service.combination; // 请确保包名正确

import jakarta.persistence.EntityNotFoundException;
import org.abc.fund.dto.combination.CombinationConverter;
import org.abc.fund.dto.combination.CombinationDetailDTO;
import org.abc.fund.dto.combination.CombinationProductDTO;
import org.abc.fund.dto.combination.RejectReasonDTO;
import org.abc.fund.entity.combination.CombinationHolding;
import org.abc.fund.entity.combination.CombinationProduct;
import org.abc.fund.entity.funds.FundBasicInfo;
import org.abc.fund.repository.combination.CombinationProductRepository;
import org.abc.fund.repository.funds.FundBasicInfoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.Instant;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 组合产品服务类。
 * 负责处理所有与组合产品相关的业务逻辑。
 * 所有公共方法的输入和输出都使用 DTO，以实现与数据库实体的解耦。
 */
@Service
public class CombinationService {

    @Autowired
    private CombinationProductRepository combinationProductRepository;

    @Autowired
    private FundBasicInfoRepository fundBasicInfoRepository;

    /**
     * 获取组合产品列表，并根据可选的状态参数进行筛选。
     * @param statusStr 产品的状态字符串，如 "PENDING_APPROVAL"
     */
    public List<CombinationProductDTO> getAllCombinationProducts(String statusStr) {
        List<CombinationProduct> products;
        if (StringUtils.hasText(statusStr)) {
            try {
                CombinationProduct.Status status = CombinationProduct.Status.valueOf(statusStr.toUpperCase());
                products = combinationProductRepository.findByStatus(status);
            } catch (IllegalArgumentException e) {
                // Handle invalid status string
                return Collections.emptyList();
            }
        } else {
            products = combinationProductRepository.findAll();
        }
        return products.stream()
                .map(CombinationConverter::toProductDTO)
                .collect(Collectors.toList());
    }

    /**
     * 批准组合产品。
     * @param id 要批准的产品ID
     * @param approverId 执行批准操作的管理员ID
     */
    @Transactional
    public void approveCombination(Long id, Long approverId) {
        CombinationProduct product = findProductByIdAndCheckStatus(id, "PENDING_APPROVAL");
        product.setStatus(CombinationProduct.Status.valueOf("APPROVED"));
        product.setApproverId(approverId);
        product.setApprovalTime(Date.from(Instant.now())); // 记录批准时间
        combinationProductRepository.save(product);
    }

    /**
     * 驳回组合产品。
     * @param id 要驳回的产品ID
     * @param rejectReasonDTO 包含驳回原因的 DTO
     * @param approverId 执行驳回操作的管理员ID
     */
    @Transactional
    public void rejectCombination(Long id, RejectReasonDTO rejectReasonDTO, Long approverId) {
        CombinationProduct product = findProductByIdAndCheckStatus(id, "PENDING_APPROVAL");
        product.setStatus(CombinationProduct.Status.valueOf("REJECTED"));
        product.setRejectionReason(rejectReasonDTO.getRejectionReason()); // 假设实体中有这个字段
        product.setApproverId(approverId);
        product.setApprovalTime(Date.from(Instant.now())); // 记录驳回时间
        combinationProductRepository.save(product);
    }

    // 辅助方法，用于减少重复代码
    private CombinationProduct findProductByIdAndCheckStatus(Long id, String expectedStatus) {
        CombinationProduct product = combinationProductRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("未找到ID为 " + id + " 的组合产品"));

        if (!expectedStatus.equals(product.getStatus().name())) {
            throw new IllegalStateException("产品当前状态为 '" + product.getStatus().name() + "', 而非期望的 '" + expectedStatus + "'，无法执行操作。");
        }
        return product;
    }

    /**
     * 根据ID获取单个组合产品的完整信息。
     * @param id 组合产品ID
     * @return 返回包含持仓详情的 DTO，如果找不到则返回 null。
     */
    @Transactional(readOnly = true)
    public CombinationDetailDTO getCombinationProductById(Long id) {
        return combinationProductRepository.findById(id)
                .map(CombinationConverter::toProductDetailDTO) // 使用转换器将实体转换为详情DTO
                .orElse(null); // 如果找不到，返回null，由Controller处理为404
    }

    /**
     * 创建一个新的组合产品。
     * @param dto 包含新产品完整信息的 DTO
     * @return 返回创建成功后、包含ID等信息的详情 DTO
     */
    @Transactional
    public CombinationDetailDTO createCombinationProduct(CombinationDetailDTO dto) {
        // 1. 创建并填充产品基本信息
        CombinationProduct product = new CombinationProduct();
        product.setName(dto.getName());
        product.setRiskLevel(dto.getRiskLevel());
        product.setStrategy(dto.getStrategy());
        product.setFeatures(dto.getFeatures());
        product.setStatus(CombinationProduct.Status.DRAFT);
        product.setCreatorId(dto.getCreatorId());

        // 2. 如果有持仓信息，则处理持仓列表
        if (dto.getHoldings() != null && !dto.getHoldings().isEmpty()) {
            List<CombinationHolding> holdings = dto.getHoldings().stream()
                    .map(holdingDto -> {
                        // 根据基金代码查找基金信息
                        FundBasicInfo fundInfo = fundBasicInfoRepository.findById(holdingDto.getFundCode())
                                .orElseThrow(() -> new EntityNotFoundException("创建组合失败：未找到基金代码为 " + holdingDto.getFundCode() + " 的基金。"));

                        // 创建持仓实体
                        CombinationHolding holding = new CombinationHolding();
                        holding.setFundCode(holdingDto.getFundCode());
                        holding.setPercentage(holdingDto.getTargetRatio());

                        // ！！！关键：建立双向关联！！！
                        holding.setCombinationProduct(product);

                        return holding;
                    }).collect(Collectors.toList());

            // 将处理好的持仓列表设置到产品中
            product.getHoldings().addAll(holdings);
        }

        // 3. 保存产品实体（JPA会因 CascadeType.ALL 级联保存持仓）
        CombinationProduct savedProduct = combinationProductRepository.save(product);

        // 4. 将保存后的实体转为 DTO 返回给前端
        return CombinationConverter.toProductDetailDTO(savedProduct);
    }

    /**
     * 更新一个已存在的组合产品。
     * @param id 要更新的产品ID
     * @param dto 包含更新后完整信息的 DTO
     * @return 返回更新成功后的详情 DTO
     */
    @Transactional
    public CombinationDetailDTO updateCombinationProduct(Long id, CombinationDetailDTO dto) {
        // 1. 根据ID从数据库中查找现有的实体，如果不存在则抛出异常
        CombinationProduct existingProduct = combinationProductRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("未找到ID为 " + id + " 的组合产品"));

        // 2. 只有 DRAFT 状态的产品才能被编辑
        if (existingProduct.getStatus() != CombinationProduct.Status.DRAFT) {
            throw new IllegalStateException("只有草稿状态的组合产品才能被编辑。");
        }

        // 3. 更新实体的基本信息
        existingProduct.setName(dto.getName());
        existingProduct.setRiskLevel(dto.getRiskLevel());
        existingProduct.setStrategy(dto.getStrategy());
        existingProduct.setFeatures(dto.getFeatures());

        // 4. 更新持仓列表 (这是最关键的部分)
        // a. 清空旧的持仓列表。由于设置了 orphanRemoval=true，JPA会自动从数据库中删除这些旧的持仓记录。
        existingProduct.getHoldings().clear();

        // b. 如果DTO中包含新的持仓信息，则将其转换为实体并添加到列表中。
        if (dto.getHoldings() != null) {
            List<CombinationHolding> newHoldings = dto.getHoldings().stream()
                    .map(holdingDto -> CombinationConverter.toHoldingEntity(holdingDto, existingProduct))
                    .collect(Collectors.toList());
            existingProduct.getHoldings().addAll(newHoldings);
        }

        // 5. 保存更新后的产品实体。JPA会处理所有变更（基本信息更新、旧持仓删除、新持仓插入）。
        CombinationProduct updatedProduct = combinationProductRepository.save(existingProduct);

        // 6. 将更新后的实体转换为DTO返回
        return CombinationConverter.toProductDetailDTO(updatedProduct);
    }

    /**
     * 提交产品以供审核。
     * @param id 要提交的产品ID
     */
    @Transactional
    public void submitForApproval(Long id) {
        CombinationProduct product = combinationProductRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("未找到ID为 " + id + " 的组合产品"));

        // 只有 DRAFT 或 REJECTED 状态的产品才能被提交
        if (product.getStatus() == CombinationProduct.Status.DRAFT || product.getStatus() == CombinationProduct.Status.REJECTED) {
            product.setStatus(CombinationProduct.Status.PENDING_APPROVAL);
            combinationProductRepository.save(product);
        } else {
            throw new IllegalStateException("只有状态为 '草稿' 或 '已驳回' 的产品才能提交审核。");
        }
    }

    /**
     * 根据ID删除一个组合产品。
     * @param id 要删除的产品ID
     */
    @Transactional
    public void deleteCombinationProduct(Long id) {
        if (!combinationProductRepository.existsById(id)) {
            throw new EntityNotFoundException("未找到ID为 " + id + " 的组合产品，无法删除。");
        }
        // 由于设置了 CascadeType.ALL，删除产品时，其关联的所有持仓也会被自动删除。
        combinationProductRepository.deleteById(id);
    }
}